package com.cloudwave.trailends.action;

import java.io.UnsupportedEncodingException;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.cloudwave.base.action.AppAction;
import com.cloudwave.base.entity.ResultEntity;
import com.cloudwave.fwcore.entity.Result;
import com.cloudwave.fwcore.utils.DateUtils;
import com.cloudwave.fwcore.utils.RegexUtils;
import com.cloudwave.fwcore.utils.security.MD5Encrypt;
import com.cloudwave.fwcore.utils.security.TokenUtils;
import com.cloudwave.trailends.domain.User;
import com.cloudwave.trailends.domain.UserRegInfo;
import com.cloudwave.trailends.domain.UserSignLog;
import com.cloudwave.trailends.entity.SsoEntity;
import com.cloudwave.trailends.service.UserInfoService;
import com.cloudwave.trailends.service.UserService;
import com.cloudwave.trailends.service.UserStatService;

/**
 * @description 用户登录，注册等
 * @author DolphinBoy
 * @date 2013-10-7
 * API版本控制参考: http://blog.csdn.net/hengyunabc/article/details/20506345
 * 基础代号:600
 */

@Controller
@RequestMapping("/api/sign")
public class SignAction extends AppAction {
	private static Logger logger = LoggerFactory.getLogger(SignAction.class);
	
	@Resource
	private UserService userService;
	@Resource
	private UserStatService userStatService;
	@Resource
	private UserInfoService userInfoService;
	
	
	/**
	 * 用户登录
	 * @param user 被加密后的[用户名+#+MD5加密之后的密码]
	 * @param key MD5加密之后的用户账号
	 * @return
	 */
	//这个方法返回的数据被浏览器识别为文件而非JSON,需要处理###
//	@RequestMapping(value="/signin")
//	@RequestMapping("/signin")
	@RequestMapping(method=RequestMethod.POST, value="/signin")
	public @ResponseBody ResultEntity signin(HttpServletRequest request
			, @RequestParam(value="username") String username
			, @RequestParam(value="password") String password
//			, @RequestParam(value="channelId", required=false) String channelId
			) {
		super.getUserSignLog().setAction(UserSignLog.ACTION_SIGNIN);
		
		// 1. 检查登录信息
		if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
			return resultEntity.failure(Result.ILLEGAL_PARAM);
//			return ResultTmpl.failure(ResultTmpl.ILLEGAL_PARAM, "非法参数!");
		}
		
		int len = 0;
		try {
			len = username.getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e1) {
			len = 0;
		}
		
		String str = RegexUtils.filterAll(username);
		int lenTmp = 0;
		try {
			lenTmp = str.getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e1) {
			lenTmp = 0;
		}
		if ( StringUtils.isEmpty(str) ) {
			return resultEntity.failure(Result.ILLEGAL_USERNAME);
		} else {
			if ( len > lenTmp ) {
				return resultEntity.failure(Result.ILLEGAL_USERNAME);
			}
		}
		
		if (len < 5 || str.length() > 25) {
			return resultEntity.failure(Result.ILLEGAL_USERNAME);
		}
		
//		if (!RegexUtils.isEmail(username)) {
//			return ResultTmpl.failure(ResultTmpl.WRONG_EMAIL, "邮箱格式错误!");
//		}
		// 2. 获取用户信息
		User user = this.userService.findByUserName(username);
//		User user = this.userService.get(1);
		
		if ( user == null ) {
//			return ResultTmpl.failure(ResultTmpl.WRONG_USERNAME, "用户不存在!");
			return resultEntity.failure(Result.UNKNOW_USER);
		}
		
		if ( !user.getPassword().equals(MD5Encrypt.encrypt(password)) ) {
//			return ResultTmpl.failure(ResultTmpl.WRONG_PASSWORD, "密码错误!");
			return resultEntity.failure(Result.WRONG_PASSWORD);
		}
		
		// 3. 异步记录登录信息-->可能用于用户行为分析
		
		
		// 4. 返回用户登录信息:此信息将被当作SESSION记录在缓存中
//		User loginInfo = new User();
//		loginInfo.setId(user.getId());
//		loginInfo.setUsername(user.getUsername());
//		loginInfo.setNickname(user.getNickname());
//		loginInfo.setEmail(user.getEmail());
//		loginInfo.setAvatar(user.getAvatar());
//		loginInfo.setToken(user.getToken());
//		loginInfo.setTotalMileage(user.getTotalMileage());
//		loginInfo.setTotalRidingLine(user.getTotalRidingLine());
//		loginInfo.setTotalLinePoint(user.getTotalLinePoint());
		
		user.setPassword(null);
		
		if ( StringUtils.isEmpty(user.getToken()) ) {
			StringBuffer token = new StringBuffer(user.getUsername()).append("|").append(user.getPassword());
			String tokenStr = TokenUtils.generateToken(token.toString());
			user.setToken(tokenStr);
			try {
				userService.updateToken(user.getId(), tokenStr);
			} catch (Exception e) {
				logger.error(e.getMessage());
				return resultEntity.failure(Result.UPDATE_FAILURE);
			}
		}
		
//		UserInfo userInfo = userInfoService.findByUserId(user.getId());
//		userInfo.setUser(loginInfo);
//		userInfo.setUserId(user.getId());
		
		//修改用户信息的最后读取时间
		//##数据库中有些字段没写入
//		try {
//			this.userInfoService.updateLastSigninTime(super.getUserId());
//		} catch (Exception e) {
//			logger.error(e.getMessage());
//		}
		
//		this.userService.updateToken(user.getId(), tokenStr);
		
		// 这里应该用切面编程或异步事件任务把详细注册信息写入到统计数据库, 记录此注册用户来自哪个渠道等
		
		return resultEntity.success(user);
	}
	
	/**
	@ResponseBody
	@RequestMapping(method = RequestMethod.POST,  value="/signin")
	public String signin(@RequestParam(value="email") String email
			, @RequestParam(value="ciphertext") String ciphertext) {
		
		// 1. 检查登录信息
		if (StringUtils.isEmpty(email) || StringUtils.isEmpty(ciphertext)) {
			return ResultTmpl.failure(ResultTmpl.NO_CERTIFIED_INFOR, "未获取到认证信息!");
		}
		
		// 2. 获取用户信息
		User user = this.userService.getByAccountOrEmail(email);
		
		if (user == null) {
			return ResultTmpl.failure(ResultTmpl.WRONG_USERNAME, "用户不存在!");
		}
		
		// 3. 解密登录信息
		byte[] decryptFrom = AesEncrypt.parseHexStr2Byte(ciphertext);
		
		AesEncrypt ae = new AesEncrypt(u.getPassword());
		String valueResult = ae.decrypt(decryptFrom);
		logger.info("解密结果："+valueResult);
		
		if (StringUtils.isEmpty(valueResult)) {
			return ResultTmpl.failure(ResultTmpl.WRONG_PASSWORD_OR_USERNAME, "非法认证信息!");
		}
		
		if (!valueResult.equalsIgnoreCase(account)) {
			return ResultTmpl.failure(ResultTmpl.WRONG_PASSWORD, "密码错误!");
		}
		
		// 4. 异步记录登录信息-->可能用于用户行为分析
		
		
		// 5. 返回用户登录信息:此信息将被当作SESSION记录在缓存中
		LoginInfo loginInfo = new LoginInfo();
		user.setPassword(null);  //把密码设置为空,减少密码在网络中的传输
		loginInfo.setUserId(user.getId());
		loginInfo.setUser(user);
		// 5.1 生成token，并返回用户信息
		StringBuffer token = new StringBuffer(user.getUsername()).append("|").append("");
		String tokenStr = TokenUtils.generateToken(token.toString());
		loginInfo.setToken(tokenStr);
		loginInfo.setCreationTime(DateUtils.now());
		loginInfo.setLastAccessedTime(DateUtils.now());
		
		//修改用户信息的最后读取时间
//		this.userInfoService.updateLastAccessedTime();
		
		return ResultTmpl.success(loginInfo);
	}
	*/
	
	/**
	 * 用户注册
	 * @param username
	 * @param password
	 * @return
	 */
	@RequestMapping(method=RequestMethod.POST, value="/signup")
	public @ResponseBody ResultEntity signup(@RequestParam(value="username") String username
//			, @RequestParam(value="email") String email
			, @RequestParam(value="password") String password
			, @RequestParam(value="needuser", defaultValue="false", required=false) Boolean needuser ) {
		
		super.getUserSignLog().setAction(UserSignLog.ACTION_SIGNUP);
		
		// 1. 验证参数合法性
		if (StringUtils.isEmpty(username)) {
			return resultEntity.failure(Result.ILLEGAL_USERNAME);
		}
		
		int len = 0;
		try {
			len = username.getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e1) {
			len = 0;
		}
		
		String str = RegexUtils.filterAll(username);
		int lenTmp = 0;
		try {
			lenTmp = str.getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e1) {
			lenTmp = 0;
		}
		if ( StringUtils.isEmpty(str) ) {
			return resultEntity.failure(Result.ILLEGAL_USERNAME);
		} else {
			if ( len > lenTmp ) {
				return resultEntity.failure(Result.ILLEGAL_USERNAME);
			}
		}
		
		if (len < 5 || len > 25) {
			return resultEntity.failure(Result.ILLEGAL_USERNAME);
		}
		
		int lenpwd = password.length();
		String pwd = RegexUtils.filtUnNcu(password);
		
		if ( pwd.length() < lenpwd ) {
			return resultEntity.failure(Result.ILLEGAL_PASSWORD);
		}
		
		if (password.length() < 5 || password.length() > 16) {
			return resultEntity.failure(Result.ILLEGAL_PASSWORD);
		}
		
		
//		if (!RegexUtils.isEmail(email)) {
//			return ResultTmpl.failure(ResultTmpl.ILLEGAL_EMAIL, "非法邮箱格式!");
//		}
		
		// 2.验证邮箱和账号是否存在
//		boolean existsEmail = this.userService.checkEmail(email);
//		if (existsEmail) {
//			return ResultTmpl.failure(ResultTmpl.REPEAT_EMAIL, "此邮箱已被注册, 请换一个试试!");
//		}
		boolean existsAccount = this.userService.isExistsAccount(username);
		if ( existsAccount ) {
			return resultEntity.failure(Result.REPEAT_ACCOUNT);
		}
		
		// 3.写入注册信息
		User user = new User();
		user.setUsername(username);  // 用户名默认使用用户邮箱, 用户登录后提示用户修改
		user.setNickname(username);
		user.setOpenid("");
		String savepwd = MD5Encrypt.encrypt(password);
		user.setPassword(savepwd);
		user.setRegtime(DateUtils.now());
		
		StringBuffer token = new StringBuffer(user.getUsername()).append("|").append(savepwd);
		String tokenStr = TokenUtils.generateToken(token.toString());
		user.setToken(tokenStr);
		
		// 这里应该用切面编程或异步事件任务把详细注册信息写入到统计数据库, 记录此注册用户来自哪个渠道等
		
		try {
			this.userService.save(user);
			
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
//			userInfo.setSignupTime(DateUtils.now());
//			//#这里有问题，数据库中有些字段没写入
//			this.userInfoService.save(userInfo);
			
			if ( needuser ) {
				User loginInfo = new User();
				loginInfo.setId(user.getId());
				loginInfo.setToken(tokenStr);
				loginInfo.setUsername(user.getUsername());
				loginInfo.setEmail(user.getEmail());
				loginInfo.setAvatar(user.getAvatar());
				
				UserRegInfo regInfo = new UserRegInfo(request);
				regInfo.setUid(loginInfo.getId());
				userStatService.saveUserRegInfo(regInfo);
				
				return resultEntity.success(loginInfo);
			} else {
				return resultEntity.success();
			}
		} catch (Exception e) {
			logger.error("保存用户异常", e);
			return resultEntity.failure(Result.SAVE_FAILURE);
		}
	}
	
	/**
	 * SSO注册或者登录
	 * @param request
	 * @param data
	 * @return
	 */
	@RequestMapping(method=RequestMethod.POST, value="/sso/sign")
	public @ResponseBody ResultEntity ssoSign(HttpServletRequest request
			, @RequestParam(value="data") String data) {
		super.getUserSignLog().setAction(UserSignLog.ACTION_SIGNUP_SSO);
		
		SsoEntity ssoEntity = JSON.parseObject(data, SsoEntity.class);
		
		User user = this.userService.findByOpenId(ssoEntity.getOpenid());
		
		if ( user == null ) {
			
			String str = RegexUtils.filterAll(ssoEntity.getNickname());
			if ( StringUtils.isEmpty(str) ) {
				return resultEntity.failure(Result.ILLEGAL_USERNAME);
			}
			
			//这里没对用户名长度进行限制###
			
			User u = new User();
			u.setUsername(str);
			u.setNickname(ssoEntity.getNickname());
			u.setAvatar(ssoEntity.getAvatar());
			u.setGender(ssoEntity.getGender());
			u.setAccessToken(ssoEntity.getToken());
			u.setOpenid(ssoEntity.getOpenid());
			u.setRegtime(DateUtils.now());
			
			StringBuffer token = new StringBuffer(u.getUsername()).append("|").append(u.getOpenid());
			String tokenStr = TokenUtils.generateToken(token.toString());
			u.setToken(tokenStr);
			
			try {
				this.userService.saveOpenUser(u);
//				
//				UserInfo userInfo = new UserInfo();
//				userInfo.setUser(user);
//				userInfo.setGender(ssoEntity.getGender());
//				userInfo.setSignupTime(DateUtils.now());
//				
//				this.userInfoService.save(userInfo);
//				
//				userInfo.setUser(user);
				
				
//				User loginInfo = new User();
//				loginInfo.setId(u.getId());
//				loginInfo.setToken(tokenStr);
//				loginInfo.setUsername(u.getUsername());
//				loginInfo.setNickname(u.getNickname());
//				loginInfo.setEmail(u.getEmail());
//				loginInfo.setAvatar(u.getAvatar());
//				loginInfo.setSignupTime(u.getSignupTime());
				
				//理论上讲应该给返回数据单独建立一个对象，这样能够在客户端改动的情况下只改动对应的模型类即可，但目前考虑到复制性暂时直接返回User对象
				
				u.setPassword(null);
				
				UserRegInfo regInfo = new UserRegInfo(request);
				regInfo.setUid(u.getId());
				regInfo.setPlatform(ssoEntity.getPlatform());
				userStatService.saveUserRegInfo(regInfo);
				
				return resultEntity.success(u);
			} catch (Exception e) {
				logger.error("保存用户异常", e);
				return resultEntity.failure(Result.SAVE_FAILURE);
			}
			
			//#这里有问题
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
//			userInfo.setSignupTime(DateUtils.now());
//			userInfo.setLastSigninTime(DateUtils.now());
//			
//			this.userInfoService.save(userInfo);
			
			
		} else {
			//这里应该修改头像、性别、昵称
			this.userService.updateAvatar(user.getId(), ssoEntity.getAvatar());
			
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
//			userInfo.setGender(ssoEntity.getGender());
//			userInfo.setSignupTime(DateUtils.now());
			
//			loginInfo.setId(user.getId());
//			loginInfo.setToken(user.getToken());
//			loginInfo.setUsername(user.getUsername());
//			loginInfo.setNickname(user.getNickname());
//			loginInfo.setEmail(user.getEmail());
//			loginInfo.setAvatar(user.getAvatar());
			
			return resultEntity.success(user);
		}
		
	}
	
	
	/**
	 * SSO登录
	 * @param request
	 * @param data
	 * @return
	 */
	@RequestMapping(method=RequestMethod.POST, value="/sso/signin")
	public @ResponseBody ResultEntity ssoSignin(HttpServletRequest request
			, @RequestParam(value="openid") String openid
			, @RequestParam(value="platform") String platform) {
		super.getUserSignLog().setAction(UserSignLog.ACTION_SIGNIN_SSO);
		
		if ( "weibo".equalsIgnoreCase(platform) 
				&& !openid.contains("weibo")) {
			openid = "weibo_"+openid;
		}
		User user = this.userService.findByOpenId(openid);
		if ( user != null ) {
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
			
//			User loginInfo = new User();
//			loginInfo.setId(user.getId());
//			loginInfo.setToken(user.getToken());
//			loginInfo.setUsername(user.getUsername());
//			loginInfo.setNickname(user.getNickname());
//			loginInfo.setEmail(user.getEmail());
//			loginInfo.setAvatar(user.getAvatar());
//			loginInfo.setSignupTime(user.getSignupTime());
			
			user.setPassword(null);
			
			if ( StringUtils.isEmpty(user.getToken()) ) {
				StringBuffer token = new StringBuffer(user.getUsername()).append("|").append(user.getPassword());
				String tokenStr = TokenUtils.generateToken(token.toString());
				user.setToken(tokenStr);
				try {
					userService.updateToken(user.getId(), tokenStr);
				} catch (Exception e) {
					logger.error(e.getMessage());
					return resultEntity.failure(Result.UPDATE_FAILURE);
				}
			}
			
			return resultEntity.success(user);
		} else {
			return resultEntity.failure(Result.UNKNOW_USER);
		}
	}
	
	/**
	 * SSO注册
	 * @param request
	 * @param data
	 * @return
	 */
	@RequestMapping(method=RequestMethod.POST, value="/sso/signup")
	public @ResponseBody ResultEntity ssoSignup(HttpServletRequest request
			, @RequestParam(value="data") String data) {
		super.getUserSignLog().setAction(UserSignLog.ACTION_SIGNUP_SSO);
		
		SsoEntity ssoEntity = JSON.parseObject(data, SsoEntity.class);
		
		User user = this.userService.findByOpenId(ssoEntity.getOpenid());
		
		if ( user == null ) {
			
			String str = RegexUtils.filterAll(ssoEntity.getNickname());
			if ( StringUtils.isEmpty(str) ) {
				return resultEntity.failure(Result.ILLEGAL_USERNAME);
			}
			
			User u = new User();
			u.setUsername(ssoEntity.getNickname());
			u.setNickname(ssoEntity.getNickname());
			u.setAvatar(ssoEntity.getAvatar());
			u.setGender(ssoEntity.getGender());
			u.setAccessToken(ssoEntity.getToken());
			u.setOpenid(ssoEntity.getOpenid());
			
			StringBuffer token = new StringBuffer(u.getUsername()).append("|").append(u.getOpenid());
			String tokenStr = TokenUtils.generateToken(token.toString());
			u.setToken(tokenStr);
			
			try {
				this.userService.saveOpenUser(u);
//				
//				UserInfo userInfo = new UserInfo();
//				userInfo.setUser(user);
//				userInfo.setGender(ssoEntity.getGender());
//				userInfo.setSignupTime(DateUtils.now());
//				
//				this.userInfoService.save(userInfo);
//				
//				userInfo.setUser(user);
				
				
//				User loginInfo = new User();
//				loginInfo.setId(u.getId());
//				loginInfo.setToken(tokenStr);
//				loginInfo.setUsername(u.getUsername());
//				loginInfo.setNickname(u.getNickname());
//				loginInfo.setEmail(u.getEmail());
//				loginInfo.setAvatar(u.getAvatar());
//				loginInfo.setSignupTime(u.getSignupTime());
				
				//理论上讲应该给返回数据单独建立一个对象，这样能够在客户端改动的情况下只改动对应的模型类即可，但目前考虑到复制性暂时直接返回User对象
				
				u.setPassword(null);
				
				UserRegInfo regInfo = new UserRegInfo(request);
				regInfo.setUid(u.getId());
				regInfo.setPlatform(ssoEntity.getPlatform());
				userStatService.saveUserRegInfo(regInfo);
				
				return resultEntity.success(u);
			} catch (Exception e) {
				logger.error("保存用户异常", e);
				return resultEntity.failure(Result.SAVE_FAILURE);
			}
			
			//#这里有问题
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
//			userInfo.setSignupTime(DateUtils.now());
//			userInfo.setLastSigninTime(DateUtils.now());
//			
//			this.userInfoService.save(userInfo);
			
			
		} else {
			this.userService.updateAvatar(user.getId(), ssoEntity.getAvatar());
			
//			UserInfo userInfo = new UserInfo();
//			userInfo.setUser(user);
//			userInfo.setGender(ssoEntity.getGender());
//			userInfo.setSignupTime(DateUtils.now());
			
//			loginInfo.setId(user.getId());
//			loginInfo.setToken(user.getToken());
//			loginInfo.setUsername(user.getUsername());
//			loginInfo.setNickname(user.getNickname());
//			loginInfo.setEmail(user.getEmail());
//			loginInfo.setAvatar(user.getAvatar());
			
			return resultEntity.success(user);
		}
		
	}
	
	/**
	 * 用手机号找回密码，在移动客户端只提供手机号找回密码的功能
	 * WEB端可以提供手机号码和邮箱两种找回密码的方式
	 * @param number 用户手机号
	 */
	
	@RequestMapping(method=RequestMethod.POST, value="/findpwd")
	public @ResponseBody ResultEntity findPassword(@RequestParam(value="number") String number) {
		if (StringUtils.isEmpty(number)) {
			return resultEntity.failure(Result.EMPTY_PARAM);
		}
		if (RegexUtils.isPhoneNumber(number)) {
			
			
			return resultEntity.success();
		} else {
			return resultEntity.failure(Result.ILLEGAL_PARAM);
		}
	}
	
}